﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Diagnostics;

namespace PDO.Utilities
{
    public static class ServiceHelper
    {
        public delegate R ActionResult<R>();
        public delegate R ActionResult<T, R>(T obj);

        /// <summary>
        /// Execute a ActionResult with WCF Exception Sheilding
        /// </summary>
        /// <typeparam name="R">Return Type</typeparam>
        /// <param name="method">Delegate method to execute</param>
        /// <param name="retry">Times to re-attempt the method if an exception is returned</param>
        /// <returns></returns>
        public static R Execute<R>(ActionResult<R> method, bool retry)
        {
            R ret;

            try
            {
                object returnValue = method.Invoke();
                ret = (R)returnValue;
            }
            catch (TimeoutException timeEx)
            {
                Logger.WriteException("Timeout occured in communications layer", "", timeEx);
                if (retry)
                {
                    return Execute<R>(method, !retry);
                }
                throw;
            }
            catch (CommunicationException commEx)
            {
                Logger.WriteException("General communications layer exception caught", "", commEx);
                if (retry)
                {
                    return Execute<R>(method, !retry);
                }
                throw;
            }            
            return ret;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T">Method Argument Type</typeparam>
        /// <typeparam name="R">Return Value Type</typeparam>
        /// <param name="method"></param>
        /// <param name="retry"></param>
        /// <param name="arg"></param>
        /// <returns></returns>
        public static R Execute<T, R>(ActionResult<T, R> method, bool retry, T arg)
        {
            R ret;

            try
            {
                object returnValue = method.Invoke(arg);
                ret = (R)returnValue;
            }
            catch (TimeoutException timeEx)
            {
                Logger.WriteException("Timeout occured in communications layer", "", timeEx);
                if (retry)
                {
                    return Execute<T, R>(method, !retry, arg);
                }
                throw;
            }
            catch (EndpointNotFoundException)
            {
                throw;
            }
            catch (CommunicationException commEx)
            {
                Logger.WriteException("General communications layer exception caught", "", commEx);
                if (retry)
                {
                    return Execute<T, R>(method, !retry, arg);
                }
                throw;
            }
            return ret;

        }
    }
}
